/*
 *		File: Descert.h
 *
 */


#ifndef __Descert__
#define __Descert__

#define NIL NULL

#include "AEObjects.h"
#include "AERegistry.h"

struct Token;

struct PrimDesc : AEDesc
{
	struct _
	{
		const OSErr		xErr;
		
		_(OSErr err) : xErr(err) { if (err != noErr) throw *this; }
		_(Handle h) : xErr(nilHandleErr) { if (h == NIL) throw *this; }
	};

	PrimDesc(void) { descriptorType = typeNull; dataHandle = NIL; }
	PrimDesc(DescType typ, const void* data, long len) { (_)AECreateDesc(typ, data, len, this); }
	PrimDesc(const AEDesc& desc) : AEDesc(desc) { }

	PrimDesc Coerce(DescType toType) const { PrimDesc	result; if (toType != result.descriptorType && toType != typeWildCard) (_)AECoerceDesc(this, toType, &result); return result; }
	PrimDesc Duplicate(void) const { PrimDesc	result; (_)AEDuplicateDesc(this, &result); return result; }

	struct ElementAccess
	{
		const DescType		desired;
		const DescType		keyForm;
		const PrimDesc&		keyData;
		ElementAccess(DescType desir, DescType form, const PrimDesc& data) : desired(desir), keyForm(form), keyData(data) { }
		ElementAccess(DescType desir, const ElementAccess& prev) : desired(desir), keyForm(prev.keyForm), keyData(prev.keyData) { }
	};
	
	struct EveryAccess : ElementAccess
	{
		static const PrimDesc	EveryDesc;
		EveryAccess(DescType desir) : ElementAccess(desir, formAbsolutePosition, EveryDesc) { }
	};

	struct PropertyAccess : ElementAccess
	{
		PropertyAccess(DescType form, const PrimDesc& data) : ElementAccess(cProperty, form, data) { }
	};

	Token operator [] (const ElementAccess& indx) const;
};


template <class T>
struct DataDesc : PrimDesc
{
	typedef PrimDesc Inherited;
	typedef T Unpacked;

	const static DescType		xPreferred;

	DataDesc(const Unpacked& data);
	DataDesc(const PrimDesc& prim) : PrimDesc(prim.Coerce(xPreferred)) { }
	
	operator Unpacked(void) { return operator *(); }
	const Unpacked& operator * (void) { (_)dataHandle; return *(Unpacked*)*dataHandle; }
	
	protected: DataDesc(void) { }
};


typedef DataDesc<DescType> TypeDesc;
typedef DataDesc<unsigned char*> NameDesc;


enum Ordinal { first = kAEFirst, last = kAELast, middle = kAEMiddle, some = kAEAny, every = kAEAll };

//################ ElementAccessor ################
template <DescType DESIRED, DescType CONTAINER>
struct ElementAccessor
{
	typedef PrimDesc::_ _;

	ElementAccessor(bool system = false)
	{
		(_)AEInstallObjectAccessor(DESIRED, CONTAINER, NewOSLAccessorProc(myOSLAccessorProc), long(this), system);
	}
	
	AEDesc Access(DescType desiredClass, const PrimDesc& container, DescType containerClass, DescType keyForm, const PrimDesc& keyData) const;

	static pascal OSErr myOSLAccessorProc(DescType desiredClass, const PrimDesc& container, DescType containerClass, DescType keyForm, const PrimDesc& keyData, AEDesc& value, const ElementAccessor& ref)
	{
		try { value = ref.Access(desiredClass, container, containerClass, keyForm, keyData); }
		catch(_& err)
			{ return err.xErr; }
		return noErr;
	}

};



#endif// __Descert__
